#include "func.h"
#include "storage.h"
#include <memory>
#include <iostream>
#include <iomanip>
#include <string>
#include "employee_factory.h"
#include <fstream>
#include <sstream>


using namespace std;


	//Implementation of Class Methods
	employee_system::employee_system(): head(nullptr),tail(nullptr) {}

	void employee_system::add_employee(std::unique_ptr<employee_base> staff)
	{
		auto new_node = std::make_unique<node>(std::move(staff));
		if (head == nullptr)
		{
			head = std::move(new_node);
			tail = head.get();
		}
		else
		{
			tail->next = std::move(new_node);
			tail = tail->next.get();
		}
	}

	void employee_system::display_employees()
	{
		node* current = head.get();
		if (current == nullptr)
		{
			std::cout << "No employees in the system." << std::endl;
			return;
		}
		while (current!= nullptr)
		{

			std::cout<< "ID:"  << current->emp->get_employee_ID() << std::setw(10) << " Name:"  << current->emp->get_name() << std::setw(40) << " department ID:"  << current->emp->get_department_ID()  << std::endl;

			current = current->next.get();
		}


	}

	void employee_system::remove_employee(const std::string& ID)
	{
		node* current = head.get();
		node* prev = nullptr;
		if (current == nullptr)
		{
			std::cout << "No employees in the system." << std::endl;
			return;
		}
		while (current!= nullptr)
		{
			if(current->emp->get_employee_ID() == ID)
			{
				if (prev == nullptr)
				{
					head = std::move(current->next);
				}
				else
				{
					prev->next = std::move(current->next);
				}
				if (current->next == nullptr)
				{
					tail = prev;
				}
				//delete current;
				std::cout << "Employee with ID " << ID << " removed successfully." << std::endl;
				return;
			}
			prev = current;
			current = current->next.get();
		}
		std::cout << "Employee with ID " << ID << " not found in the system." << std::endl;
	}

	//The basic implementation is similar to deletion, just make modifications and changes
	//Okay, I retract the previous sentence,The difficulty lies in the conversion between subclasses

	void employee_system::modify_employee(const std::string &ID)
	{
		
		node* current = head.get();
		node* prev = nullptr;
		if (current == nullptr)
		{
			std::cout << "No employees in the system." << std::endl;
			return;
		}
		while (current!= nullptr)
		{
			if(current->emp->get_employee_ID() == ID)
			{
				string name, department_ID,new_ID,position;
				std::cout << "Enter name: " << std::endl;
				std::cin >> name;
				std::cout << "Enter department ID: " << std::endl;
				std::cin >> department_ID;
				std::cout << "Enter ID: " << std::endl;
				std::cin >> new_ID;
				std::cout << "Please enter the position of this employee, from 1 to 3, corresponding to boss, manager, and employee" << std::endl;
				while (true)
				{
				std::cin >> position;
				if(position == "1" || position == "2" || position == "3")
				{
					break;
				}else{
						std::cout << "Invalid input, please enter a number from 1 to 3" << std::endl;
					}
				}

				//current->emp->set_name(name);
				//current->emp->set_department_ID(department_ID);
				//current->emp->set_employee_ID(new_ID);
				current->emp = EmployeeFactory::create_employee(name, department_ID, new_ID, position);
				

				std::cout << "Employee with ID " << ID << " modify successfully." << std::endl;
				return;
			}
			prev = current;
			current = current->next.get();
		}
	}

	void employee_system::search_employee(const std::string& ID){
		node* current = head.get();
		
		if (current == nullptr)
		{
			std::cout << "No employees in the system." << std::endl;
			return;
		}
		while (current!= nullptr)
		{
			if(current->emp->get_employee_ID() == ID)
			{
				std::cout << "ID:"  << current->emp->get_department_ID() << std::setw(10) << " Name:"  << current->emp->get_name() << std::setw(40) << " department ID:"  << current->emp->get_department_ID()  << std::endl;
				return;
			}
			
			current = current->next.get();
		}	
		std::cout << "Employee with ID " << ID << " not found in the system." << std::endl;
	}

	
/*
	employee_system::node* employee_system::split(node* head) {
		if (!head || !head->next) return nullptr;

		node* slow = head;
		node* fast = head->next.get();
		node* prev = nullptr;

		while (fast && fast->next) {
			prev = slow;
			slow = slow->next.get();
			fast = fast->next->next.get();
		}

		if (prev) {
			prev->next.reset(); // �Ͽ�����
		}

		std::ostringstream oss;
		if (slow) {
			oss << "Splitting at node with ID: " << slow->emp->get_employee_ID();
		}
		else {
			oss << "Splitting at node with ID: nullptr";
		}
		std::cout << oss.str() << std::endl;

		return slow; // �����Ұ벿�ֵ�ͷ���
	}

	employee_system::node* employee_system::merge(node* left, node* right) {
		if (!left) return right;
		if (!right) return left;

		std::ostringstream oss;
		if (left->emp->get_employee_ID() < right->emp->get_employee_ID()) {
			left->next = std::unique_ptr<node>(merge(left->next.release(), right));
			oss << "Merging nodes: " << left->emp->get_employee_ID() << " and " << right->emp->get_employee_ID();
			std::cout << oss.str() << std::endl;
			return left;
		}
		else {
			right->next = std::unique_ptr<node>(merge(left, right->next.release()));
			oss << "Merging nodes: " << right->emp->get_employee_ID() << " and " << left->emp->get_employee_ID();
			std::cout << oss.str() << std::endl;
			return right;
		}
	}

	employee_system::node* employee_system::merge_sort(node* head) {
		if (!head || !head->next) return head;

		std::ostringstream oss;
		oss << "Merge sorting list starting with head ID: " << head->emp->get_employee_ID();
		std::cout << oss.str() << std::endl;

		node* middle = split(head);
		node* left = merge_sort(head);
		node* right = merge_sort(middle);

		std::ostringstream oss_merge;
		if (left && right) {
			oss_merge << "Merging lists with head IDs: " << left->emp->get_employee_ID()
				<< " and " << right->emp->get_employee_ID();
		}
		else if (left) {
			oss_merge << "Merging lists with head ID: " << left->emp->get_employee_ID() << " and nullptr";
		}
		else if (right) {
			oss_merge << "Merging lists with head ID: nullptr and " << right->emp->get_employee_ID();
		}
		else {
			oss_merge << "Merging lists with head IDs: nullptr and nullptr";
		}
		std::cout << oss_merge.str() << std::endl;

		return merge(left, right);
	}

	void employee_system::sort_employees() {
		if (!head) return;
		std::cout << "Starting sort_employees()" << std::endl;
		head = std::unique_ptr<node>(merge_sort(head.release()));
		node* current = head.get();
		while (current && current->next) {
			current = current->next.get();
		}
		tail = current;
		std::cout << "Completed sort_employees()" << std::endl;
	}
*/
	void employee_system::delete_all_employees(){
		head.reset();
		tail = nullptr;
		std::cout << "All employees removed successfully." << std::endl;
	}

/*
	void employee_system::init_system(){
		std::ifstream infile("employee_system.txt", std::ios::in|std::ios::binary);
		if(!infile.is_open()){
			return;
		}
		while(true)
		{
			size_t id_size;
			infile.read(reinterpret_cast<char *>(&id_size), sizeof(id_size));
			if(infile.eof())break;
			std::string emp_ID(id_size, '0');
			infile.read(&emp_ID[0], id_size);

			size_t name_length;
        	infile.read(reinterpret_cast<char*>(&name_length), sizeof(name_length));
        	std::string name(name_length, '\0');
        	infile.read(&name[0], name_length);

			size_t department_ID_length;
			infile.read(reinterpret_cast<char *>(&department_ID_length), sizeof(department_ID_length));
			std::string department_ID(department_ID_length, '0');
			infile.read(&department_ID[0], department_ID_length);

			size_t position_length;
			infile.read(reinterpret_cast<char *>(&position_length), sizeof(position_length));
			std::string position(position_length, '0');
			infile.read(&position[0], position_length);

			std::unique_ptr<employee_base> emp = EmployeeFactory::create_employee(name, department_ID, emp_ID, position);
			add_employee(std::move(emp));

		}
		infile.close();
	}

*/

void employee_system::init_system() {
    std::ifstream infile("employee_system.txt", std::ios::in | std::ios::binary);
    if (!infile.is_open()) {
        std::cerr << "Error opening file for reading." << std::endl;
        return;
    }

    while (true) {
        size_t id_size;
        infile.read(reinterpret_cast<char*>(&id_size), sizeof(size_t));
        if (infile.eof()) break;
        if (!infile) {
            std::cerr << "Error reading employee ID size." << std::endl;
            break;
        }
        std::string emp_ID(id_size, '\0');
        infile.read(&emp_ID[0], id_size);
        if (!infile) {
            std::cerr << "Error reading employee ID." << std::endl;
            break;
        }

        size_t name_length;
        infile.read(reinterpret_cast<char*>(&name_length), sizeof(name_length));
        if (!infile) {
            std::cerr << "Error reading employee name length." << std::endl;
            break;
        }
        std::string name(name_length, '\0');
        infile.read(&name[0], name_length);
        if (!infile) {
            std::cerr << "Error reading employee name." << std::endl;
            break;
        }

        size_t department_ID_length;
        infile.read(reinterpret_cast<char*>(&department_ID_length), sizeof(department_ID_length));
        if (!infile) {
            std::cerr << "Error reading department ID length." << std::endl;
            break;
        }
        std::string department_ID(department_ID_length, '\0');
        infile.read(&department_ID[0], department_ID_length);
        if (!infile) {
            std::cerr << "Error reading department ID." << std::endl;
            break;
        }

        size_t position_length;
        infile.read(reinterpret_cast<char*>(&position_length), sizeof(position_length));
        if (!infile) {
            std::cerr << "Error reading position length." << std::endl;
            break;
        }
        std::string position(position_length, '\0');
        infile.read(&position[0], position_length);
        if (!infile) {
            std::cerr << "Error reading position." << std::endl;
            break;
        }

        auto emp = EmployeeFactory::create_employee(name, emp_ID ,department_ID, position);
        if (!emp) {
            std::cerr << "Error creating employee object." << std::endl;
            break;
        }
        add_employee(std::move(emp));
    }
    infile.close();
}

/*
	void employee_system::exit_system(){
		std::ofstream outfile("employee_system.txt", std::ios::out|std::ios::binary);
		if(!outfile.is_open()){
			return;
		}
		node* current = head.get();
		while(current != nullptr){

			//outfile.write((char*)&current->emp->get_employee_ID(), sizeof(std::string));
			std::string emp_ID = current->emp->get_employee_ID();
			size_t id_size = emp_ID.size();
			//outfile.write((char*)&id_size, sizeof(size_t));
			outfile.write(reinterpret_cast<const char*>(&id_size), sizeof(id_size));
			outfile.write(emp_ID.c_str(), id_size);
			
			//outfile.write((char*)&current->emp->get_name(), sizeof(std::string));
			std::string name = current->emp->get_name();
			size_t name_size = name.size();
			//outfile.write((char*)&name_size, sizeof(size_t));
			outfile.write(reinterpret_cast<const char*>(&name_size), sizeof(name_size));
			outfile.write(name.c_str(), name_size);
			
			//outfile.write((char*)&current->emp->get_department_ID(), sizeof(std::string));
			std::string department_ID = current->emp->get_department_ID();
			size_t department_ID_size = department_ID.size();
			//outfile.write((char*)&department_ID_size, sizeof(size_t));
			outfile.write(reinterpret_cast<const char*>(&department_ID_size), sizeof(department_ID_size));
			outfile.write(department_ID.c_str(), department_ID_size);

			//outfile.write((char*)&current->emp->get_position(), sizeof(string));
			if(dynamic_cast<boss*>(current->emp.get()))
			{
				outfile.write((char*)&"1", sizeof(std::string));
			}
			else if(dynamic_cast<manager*>(current->emp.get()))
			{
				outfile.write((char*)&"2", sizeof(std::string));
			}
			else if(dynamic_cast<employee*>(current->emp.get()))
			{
				outfile.write((char*)&"3", sizeof(std::string));
			}
			current = current->next.get();
		}
		outfile.close();

	}

*/

void employee_system::exit_system() {
    std::ofstream outfile("employee_system.txt", std::ios::out | std::ios::binary);
    if (!outfile.is_open()) {
        std::cerr << "Error opening file for writing." << std::endl;
        return;
    }

    node* current = head.get();
    while (current != nullptr) {
        const std::string& emp_ID = current->emp->get_employee_ID();
        size_t id_size = emp_ID.size();
        outfile.write(reinterpret_cast<const char*>(&id_size), sizeof(id_size));
        outfile.write(emp_ID.c_str(), id_size);

        const std::string& name = current->emp->get_name();
        size_t name_length = name.size();
        outfile.write(reinterpret_cast<const char*>(&name_length), sizeof(name_length));
        outfile.write(name.c_str(), name_length);

        const std::string& department_ID = current->emp->get_department_ID();
        size_t department_ID_length = department_ID.size();
        outfile.write(reinterpret_cast<const char*>(&department_ID_length), sizeof(department_ID_length));
        outfile.write(department_ID.c_str(), department_ID_length);

        std::string position;
        if (dynamic_cast<boss*>(current->emp.get())) {
            position = "1";
        } else if (dynamic_cast<manager*>(current->emp.get())) {
            position = "2";
        } else if (dynamic_cast<employee*>(current->emp.get())) {
            position = "3";
        }
        size_t position_length = position.size();
        outfile.write(reinterpret_cast<const char*>(&position_length), sizeof(position_length));
        outfile.write(position.c_str(), position_length);

        current = current->next.get();
    }
    outfile.close();
}

void employee_system::work(const std::string& ID){
	node* current = head.get();
	if (current == nullptr)
	{
		std::cout << "No employees in the system." << std::endl;
		return;
	}
	while ( current!= nullptr)
	{
		if(current->emp->get_employee_ID() == ID)
		{
			current->emp->duty();
			return;
		}
		current = current->next.get();
	}
	std::cout << "Employee with ID " << ID << " not found in the system." << std::endl;
	}


void employee_system::sort_employees() {
    if (!head) return;

    node* sorted = nullptr;  // 初始化已排序链表为空
    node* current = head.release();  // 取出原链表的头节点

    while (current) {
        node* next = current->next.release();  // 保存当前节点的下一个节点
        current->next.reset();  // 将当前节点的 next 置空，断开与原链表的链接

        // 在已排序链表中找到插入点
        if (!sorted || sorted->emp->get_employee_ID() >= current->emp->get_employee_ID()) {
            current->next.reset(sorted);
            sorted = current;
        } else {
            node* temp = sorted;
            while (temp->next && temp->next->emp->get_employee_ID() < current->emp->get_employee_ID()) {
                temp = temp->next.get();
            }
            current->next.reset(temp->next.release());
            temp->next.reset(current);
        }

        current = next;  // 继续处理原链表中的下一个节点
    }

    head.reset(sorted);  // 将已排序链表的头节点赋给 head

    // 更新 tail
    tail = head.get();
    while (tail && tail->next) {
        tail = tail->next.get();
    }
}

bool employee_system::check_emp(const std::string& ID) {

    node* current = head.get();
    if (current == nullptr) {
        //std::cout << "No employees in the system." << std::endl;
        return false;
	}
	while (current != nullptr)
	{
		if(current->emp->get_employee_ID() == ID)
		{
			return true;
		}
		current = current->next.get();
	}
	return false;
}